package com.xiaoming.project.core.thread;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 生产者、消费者模型
 * 线程通信的其他模型还有什么呢？
 *
 * 输入一串数字，每个线程负责打印一个数字，让程序可以正常打印这些数字
 */
public class ThreadPrintNumber {

    private static BlockingDeque<Integer> printNumber = new LinkedBlockingDeque<>();

    public static void main(String[] args) {
        threadPrintNumbers("1214214212135425");
    }


    public static void threadPrintNumbers(String numbers) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10,
                                                                       5,
                                                                       TimeUnit.SECONDS,
                                                                       new LinkedBlockingDeque<Runnable>());
        Stream.iterate(0, integer -> integer + 1).limit(10)
                .map(PrintNumber::valueOf)
                .forEach(threadPoolExecutor::execute);

        Arrays.stream(numbers.split("")).map(Integer::valueOf)
              .forEach(printNumber::add);

        threadPoolExecutor.shutdown();
    }

    static class PrintNumber implements Runnable {

        private Integer number;

        public static PrintNumber valueOf(Integer number) {
            PrintNumber printNumber = new PrintNumber();
            printNumber.number = number;
            return printNumber;
        }

        /**
         * 对待打印队列的数据需要添加同步控制，保证读取、打印、弹出这三个动作是原子的，才能保证线程的执行顺序
         */
        public synchronized void print() {
            if (Objects.equals(printNumber.peek(), number)) {
                System.out.printf("thread_name:%s, printNumber:%s",
                                  Thread.currentThread().getName(), number);
                System.out.println();
                printNumber.pop();
            }
        }

        @Override
        public void run() {
            while (true) {
                print();
            }
        }

    }

}